import sys
import collections
def check(threshold: int, grid: list[list[int]], n: int) -> bool:
    """
    检查是否存在一条从 (0,0) 到 (n-1, n-1) 的路径，
    使得路径上所有单元格的海拔高度都小于或等于 threshold。
    """
    # 如果起点本身的海拔就高于阈值，则无法开始，直接返回 False
    if grid[0][0] > threshold:
        return False

    q = collections.deque()
    q.append((0, 0))  # 队列存储 (行, 列)

    # visited 数组用于避免重复访问和循环，防止无限循环
    visited = [[False] * n for _ in range(n)]
    visited[0][0] = True

    # 定义四个方向的移动
    dr = [-1, 1, 0, 0]  # 行方向的偏移量 (上, 下, 左, 右)
    dc = [0, 0, -1, 1]  # 列方向的偏移量 (上, 下, 左, 右)

    while q:
        r, c = q.popleft()  # 取出当前单元格

        # 如果到达终点，则说明存在满足条件的路径
        if r == n - 1 and c == n - 1:
            return True

        # 遍历四个邻居
        for i in range(4):
            nr, nc = r + dr[i], c + dc[i]

            # 检查邻居是否在网格范围内、未被访问过，并且海拔高度满足阈值条件
            if 0 <= nr < n and 0 <= nc < n and not visited[nr][nc] and grid[nr][nc] <= threshold:
                visited[nr][nc] = True  # 标记为已访问
                q.append((nr, nc))  # 将邻居加入队列

    # 如果队列为空，但未到达终点，则说明不存在满足条件的路径
    return False

def shortestTimeToEvacuate_optimized(grid: list[list[int]]) -> int:
    n = len(grid)

    # 确定二分查找的范围 [low, high]
    # low 的最小值是起点的高度，因为路径必须经过起点
    # high 的最大值是整个网格中的最高海拔，作为可能的上限
    low = grid[0][0]
    high = 0
    for r in range(n):
        for c in range(n):
            high = max(high, grid[r][c])

    ans = high  # 初始化答案为最坏情况下的可能解 (即最大海拔)

    # 进行二分查找
    while low <= high:
        mid = low + (high - low) // 2  # 计算中间值，避免溢出

        # 检查当前 mid 作为最大海拔阈值是否可行
        if check(mid, grid, n):
            ans = mid  # 如果可行，则 mid 是一个可能的答案，尝试更小的阈值
            high = mid - 1
        else:
            low = mid + 1  # 如果不可行，则需要更大的阈值

    return ans


# --- ACM 模式下的输入读取 ---
# 读取 N
N = int(sys.stdin.readline().strip())
# 创建 grid
grid = []
for _ in range(N):
    row = list(map(int, sys.stdin.readline().strip().split()))
    grid.append(row)

# 调用优化后的函数并输出结果
result = shortestTimeToEvacuate_optimized(grid)
print(result)

